{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 2, Topic 1, Lab A: Instruction Power Differences (MAIN)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *Now that you've been introduced to the ChipWhisperer platform, we'll be using it to learn more about how the power consumed by a microcontroller varies based on what operations it is performing and what instructions it is executing.*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* Capturing a power trace with ChipWhisperer\n",
    "* Making connections between various simple instructions and power traces"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prerequisites\n",
    "\n",
    "Hold up! Before you continue, check you've done the following tutorials:\n",
    "\n",
    "* ☑ Jupyter Notebook Intro (you should be OK with plotting & running blocks).\n",
    "* ☑ SCA101 Intro (you should have an idea of how to get hardware-specific versions running)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "At this point you've got to insert code to perform the power trace capture. There are two options here:\n",
    "* Capture from physical device.\n",
    "* Read from a file.\n",
    "\n",
    "You get to choose your adventure - see the two notebooks with the same name of this, but called `(SIMULATED)` or `(HARDWARE)` to continue. Inside those notebooks you should get some code to copy into the following section, which will define the capture function.\n",
    "\n",
    "Be sure you get the `\"✔️ OK to continue!\"` print once you run the cell afterwards, otherwise things will fail later on!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CW308_SAM4S'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "cd ../../../firmware/mcu\n",
    "mkdir -p simpleserial-base-lab2 && cp -r simpleserial-base/* $_\n",
    "cd simpleserial-base-lab2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\"\n",
    "cd ../../../firmware/mcu/simpleserial-base-lab2\n",
    "make PLATFORM=$1 CRYPTO_TARGET=NONE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "try:\n",
    "    if not scope.connectStatus:\n",
    "        scope.con()\n",
    "except NameError:\n",
    "    scope = cw.scope()\n",
    "   \n",
    "try:\n",
    "    target = cw.target(scope)\n",
    "except IOError:\n",
    "    print(\"INFO: Caught exception on reconnecting to target - attempting to reconnect to scope first.\")\n",
    "    print(\"INFO: This is a work-around when USB has died without Python knowing. Ignore errors above this line.\")\n",
    "    scope = cw.scope()\n",
    "    target = cw.target(scope)\n",
    "\n",
    "print(\"INFO: Found ChipWhisperer😍\")\n",
    "\n",
    "if \"STM\" in PLATFORM or PLATFORM == \"CWLITEARM\" or PLATFORM == \"CWNANO\":\n",
    "    prog = cw.programmers.STM32FProgrammer\n",
    "elif PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "    prog = cw.programmers.XMEGAProgrammer\n",
    "elif \"neorv32\" in PLATFORM.lower():\n",
    "    prog = cw.programmers.NEORV32Programmer\n",
    "elif PLATFORM == \"CW308_SAM4S\" or PLATFORM == \"CWHUSKY\":\n",
    "    prog = cw.programmers.SAM4SProgrammer\n",
    "else:\n",
    "    prog = None\n",
    "    \n",
    "import time\n",
    "time.sleep(0.05)\n",
    "scope.default_setup()\n",
    "\n",
    "if PLATFORM == \"CW308_SAM4S\" or PLATFORM == \"CWHUSKY\":\n",
    "    scope.io.target_pwr = 0\n",
    "    time.sleep(0.2)\n",
    "    scope.io.target_pwr = 1\n",
    "    time.sleep(0.2)\n",
    "def reset_target(scope):\n",
    "    if PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "        scope.io.pdic = 'low'\n",
    "        time.sleep(0.1)\n",
    "        scope.io.pdic = 'high_z' #XMEGA doesn't like pdic driven high\n",
    "        time.sleep(0.1) #xmega needs more startup time\n",
    "    elif \"neorv32\" in PLATFORM.lower():\n",
    "        raise IOError(\"Default iCE40 neorv32 build does not have external reset - reprogram device to reset\")\n",
    "    elif PLATFORM == \"CW308_SAM4S\" or PLATFORM == \"CWHUSKY\":\n",
    "        scope.io.nrst = 'low'\n",
    "        time.sleep(0.25)\n",
    "        scope.io.nrst = 'high_z'\n",
    "        time.sleep(0.25)\n",
    "    else:  \n",
    "        scope.io.nrst = 'low'\n",
    "        time.sleep(0.05)\n",
    "        scope.io.nrst = 'high_z'\n",
    "        time.sleep(0.05)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, \"../../../firmware/mcu/simpleserial-base-lab2/simpleserial-base-{}.hex\".format(PLATFORM))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def capture_trace(_ignored=None):\n",
    "    ktp = cw.ktp.Basic()\n",
    "    key, text = ktp.next()\n",
    "    return cw.capture_trace(scope, target, text).wave"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wave = capture_trace()\n",
    "print(\"✔️ OK to continue!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## \"Empty\" Trace\n",
    "\n",
    "As you saw in earlier labs, the `simpleserial-base` firmware echos what we send to it. For this lab, we just want to focus on simple instructions, rather than serial communication. Open `simpleserial-base.c` in the `simpleserial-base-lab2` folder, navigate to the `get_pt()` function, and remove the `simpleserial_put()` call.\n",
    "\n",
    "Rebuild the firmware and upload it to the target. Capture a trace, and we can plot it using the following code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.plot(wave)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You shouldn't see much happening here before the target starts idling."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simple Instructions\n",
    "\n",
    "To start off, let's insert some simple instructions to see if they're visible in the power trace. We're mostly looking for an instruction that executes in a single cycle, which will depend on what platform you're using for this lab. For an ARM device, try inserting the following code, which will execute 20 multiplies. It's important to mark `A` as `volatile` here to prevent the compiler from optimizing all these instructions out:\n",
    "\n",
    "```C\n",
    "\tvolatile long int A = 0x2BAA;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\t\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\t\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "\tA *= 2;\n",
    "```\n",
    "\n",
    "For the XMEGA/AVR, multiply is a more expensive instruction, so insert the following code instead:\n",
    "\n",
    "```C\n",
    "\n",
    "\tvolatile long int A = 0x2BAA;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\t\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\t\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "\tA += 2;\n",
    "```\n",
    "\n",
    "Then rebuild, capture a new trace, and plot it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wave2 = capture_trace()\n",
    "\n",
    "cw.plot(wave2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Depending on your target, there might not be much difference here. You may want to plot both traces on the same plot:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.plot(wave) * cw.plot(wave2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simple Instruction Loop\n",
    "\n",
    "You might think that it's strange that we didn't simply use a loop instead of copying the same thing out 20 times. Rectify this by replacing these instructions with a loop. **Make sure to make the loop variable volatile as well.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wave3 = capture_trace()\n",
    "cw.plot(wave3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Are you surprised by how different the loop is from just repeatedly performing operations? If you're comfortable with assembly, you can check the `.lss` file in the `simpleserial-base-lab2` directory. Otherwise, here's a C level overview of what (depending on how your compiler lays things out) the loop acutally looks like:\n",
    "\n",
    "```C\n",
    "i=0;\n",
    "start:\n",
    "    if (i > 20) {\n",
    "        goto end;\n",
    "    }    \n",
    "    A *= 2;\n",
    "    i += 1;\n",
    "    goto start;\n",
    "end:\n",
    "    trigger_low();\n",
    "    //...\n",
    "```\n",
    "\n",
    "As you can see, the microcontroller has to do a lot more than simply repeating our instruction. As such, it's something a compiler will often \"unroll\" (basically turn it back into our original repeated multiplies). In our case, since `i` was marked as `volatile`, the compiler avoided making this optimization. Unrolling loops also increases code size, so the compiler might also avoid unrolling when optimizing for code size."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Expensive Instructions\n",
    "\n",
    "Up to now, all the instructions we've used (besides branches in the loop) have executed in a single clock cycle. Instead, let's try an instruction that takes multiple clock cycles to execute. This will be platform specific, but for an ARM device, a divide will work well. The AVR/XMEGA doesn't actually have a divide instruction, so you'll want to use something like a multiply instead."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wave4 = capture_trace()\n",
    "cw.plot(wave4) * cw.plot(wave3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can probably see a similar pattern to the faster instruction, but each go through the loop takes longer. We would also expect that longer instructions would also consume more power. Can you see this in your plot?\n",
    "\n",
    "**HINT: In order to measure current, ChipWhisperer measures voltage drop across a shunt resistor. This means that the power trace is actually inverted (aka large negative swings are areas of higher power consumption).**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusions & Next Steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By now you should be reasonably convinced that we can gain some understanding of what a microcontroller is doing by looking at its power consumption. Going forward, we'll be focusing on more objective measurements, but what we did in this lab is still very valuable. AES implementations, for example, will often have a very distinct shape. You can use this to help identify what an unknown device is doing at different times.\n",
    "\n",
    "Of course, there's a lot more you can do with this lab. For example, does an add look any different from an XOR? Next time, we'll be using what we learned in this lab to break a simple password check."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<small>NO-FUN DISCLAIMER: This material is Copyright (C) NewAE Technology Inc., 2015-2020. ChipWhisperer is a trademark of NewAE Technology Inc., claimed in all jurisdictions, and registered in at least the United States of America, European Union, and Peoples Republic of China.\n",
    "\n",
    "Tutorials derived from our open-source work must be released under the associated open-source license, and notice of the source must be *clearly displayed*. Only original copyright holders may license or authorize other distribution - while NewAE Technology Inc. holds the copyright for many tutorials, the github repository includes community contributions which we cannot license under special terms and **must** be maintained as an open-source release. Please contact us for special permissions (where possible).\n",
    "\n",
    "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</small>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
